﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Super_Pong.Classes
{
    class Particle : Entity
    {
        #region Attributes
        private float angle;
        private bool alive;
        private long lifeTime;
        private long existingTime;
        private float rotationVelocity;
        private Vector2 origin;

        private float startSize;
        private float endSize;

        private Color startColor;
        private Color endColor;

        private BlendState blend;
        private bool followDirection;
        #endregion

        #region Constructors
        /// <summary>
        /// A customizable particle.
        /// </summary>
        /// <param name="anim">The particle animation. How it looks like.</param>
        /// <param name="startPos">The position were the particle starts.</param>
        /// <param name="lifeTime">The particle life time in milliseconds.</param>
        /// <param name="rotVel">The particle rotation velocity.</param>
        /// <param name="fDirection">If true the particle will face the direction it's going.</param>
        /// <param name="startSize">The particle initial size.</param>
        /// <param name="endSize">The particle ending size.</param>
        /// <param name="StartColor">The initial particle color.</param>
        /// <param name="EndColor">The final particle color.</param>
        /// <param name="bls">The particle blend style.</param>
        public Particle(Animation anim, Vector2 startPos,long lifeTime, float rotVel, bool fDirection, float startSize, float endSize, Color StartColor, Color EndColor, BlendState bls)
        {
            //Set all default values
            existingTime = 0L;
            angle = 0.0f;
            alive = true;

            //Grab parameters
            this.setAnimation(anim);
            this.setPosition(startPos);
            this.lifeTime = lifeTime;
            this.startSize = startSize;
            this.endSize = endSize;
            startColor = StartColor;
            endColor = EndColor;
            rotationVelocity = rotVel;
            followDirection = fDirection;

            //Grab the blend state
            if (bls == null)
                blend = BlendState.AlphaBlend;
            else
                blend = bls;

            //Set the image origin to its center
            if(getAnimation() != null)
                origin = new Vector2(getWidth()/2,getHeight()/2);
        }

        /// <summary>
        /// A customizable particle.
        /// </summary>
        /// <param name="anim">The particle animation. How it looks like.</param>
        /// <param name="startPos">The position were the particle starts.</param>
        /// <param name="lifeTime">The particle life time in milliseconds.</param>
        /// <param name="rotVel">The particle rotation velocity.</param>
        /// <param name="startSize">The particle initial size.</param>
        /// <param name="endSize">The particle ending size.</param>
        /// <param name="StartColor">The initial particle color.</param>
        /// <param name="EndColor">The final particle color.</param>
        /// <param name="bls">The particle blend style.</param>
        public Particle(Animation anim, Vector2 startPos, long lifeTime, float rotVel, float startSize, float endSize, Color StartColor, Color EndColor, BlendState bls)
        {
            //Set all default values
            existingTime = 0L;
            angle = 0.0f;
            alive = true;

            //Grab parameters
            this.setAnimation(anim);
            this.setPosition(startPos);
            this.lifeTime = lifeTime;
            this.startSize = startSize;
            this.endSize = endSize;
            startColor = StartColor;
            endColor = EndColor;
            rotationVelocity = rotVel;
            followDirection = false;

            //Grab the blend state
            if (bls == null)
                blend = BlendState.AlphaBlend;
            else
                blend = bls;

            //Set the image origin to its center
            if (getAnimation() != null)
                origin = new Vector2(getWidth() / 2, getHeight() / 2);
        }
        #endregion

        #region Methods

        /// <summary>
        /// Basic response to collision. Work only when the particle have
        /// collision enabled.
        /// </summary>
        /// <param name="e">An entity to check AND react to collision.</param>
        public override void collide(Entity e)
        {
            //Invert this guy direction
            this.setDirection(-this.getDirection());

            //Remove the collision (POG)
            this.move(this.getDirection() * 1.2f);
        }

        /// <summary>
        /// Get the life percent of this particle existence.
        /// </summary>
        /// <returns>The percent given by this formula: existingTime / lifeTime </returns>
        public float getLifePercent()
        {
            return ((float)existingTime) / ((float)lifeTime);
        }

        /// <summary>
        /// Update the particle.
        /// </summary>
        /// <param name="elapsedTime">GameTime object.</param>
        public override void Update(GameTime elapsedTime)
        {
            //Check for live particles only!
            if (alive)
            {

                //Update the particle anim
                getAnimation().Update(elapsedTime);

                //Update the lifeTime
                if (existingTime < lifeTime)
                    existingTime += elapsedTime.ElapsedGameTime.Milliseconds;
                else
                    alive = false;

                //Move the particle
                move(getDirection() * getSpeed() * elapsedTime.ElapsedGameTime.Milliseconds);

                //Rotate the particle
                if (followDirection)
                {
                    //angle = (float)Math.Acos(getDirection().Y);
                    angle = (float)Math.Asin(-getDirection().X);
                }
                else
                {
                    angle += rotationVelocity;
                    angle = angle % 360;
                }
            }
        }

        /// <summary>
        /// Draw the particle to the screen.
        /// </summary>
        /// <param name="sb">A batch to draw on.</param>
        public override void Draw(SpriteBatch sb)
        {
            //Draw this particle
            if (alive)
            {
                //Set the image origin to its center
                if(origin == null)
                    origin = new Vector2(getWidth()/2,getHeight()/2);
                
                //Begin our drawing process
                sb.Begin(SpriteSortMode.FrontToBack, blend);
                sb.Draw(this.getImage(), this.getPosition(), null, Utils2D.lerpColor(startColor, endColor, getLifePercent()),
                    angle, origin, Utils2D.lerp(startSize, endSize, getLifePercent()), SpriteEffects.None, 1f);
                sb.End();
            }
        }

        #endregion

        #region Gets and Sets
        /// <summary>
        /// Returns true if the particle is alive.
        /// </summary>
        /// <returns>True or false depending on the particle alive status.</returns>
        public bool isAlive()
        {
            return alive;
        }

        /// <summary>
        /// Set this particle angle.
        /// </summary>
        /// <param name="a">The angle to set to.</param>
        public void setAngle(float a){
            this.angle = a;
        }
        #endregion
    }
}
